#pragma once
#include <list>
#include "util.h"
#include <ptr_container/ptr_vector.hpp>
#include <lambda/lambda.hpp>
#include <lambda/bind.hpp>
#include <lambda/construct.hpp>
#include <vector>
/*///////////////////////////////////////////
same way to use as event
but we have more
We can add a listener to a specified catalog, and we can notify a specified catalog now.
Please refer to the KeyboardListener.h and KeyboardSource.h and KeyboardSource.cpp to find the usage.

*///////////////////////////////////////////
using namespace std;
template <class ConMutiSource,class ConMutiListener,class Param=Null>
class IMutiListener;

template <class ConSource,class Listener,size_t nEvent=1,class EventClass=Null>
class MutiSource;
/*/Policy for Event class/*/
template <class ConSource,class Event>
class MutiEventPolicy
{
public:
	typedef Event EventType;
protected:
	virtual EventType& getEvent()=0;
	~MutiEventPolicy(){};
};

template <class ConSource>
class MutiEventPolicy<ConSource,Null>
{
public:
	typedef ConSource EventType;
protected:
	EventType& getEvent(){return *((ConSource*)this);}
	~MutiEventPolicy(){};
};

template <class ConMutiSource,class ConMutiListener,size_t nEvent,class EventClass>
class MutiSource:public MutiEventPolicy<ConMutiSource,EventClass>
{
		typedef ConMutiListener Listener;
	public:
		MutiSource()
			:m_nCatalog(nEvent)
		{
			for(size_t i=0;i<nEvent;i++)
			{
				m_listenerCatalog.push_back(new list<Listener* const>);
			}
		}

		//typedef EventClass EventType;
		void add(Listener*const listener, size_t catalog)
		{
			m_listenerCatalog[catalog].push_back (listener);
		}

		void remove(Listener*const listener, size_t catalog)
		{
			m_listenerCatalog[catalog].remove(listener);
		}

		static const size_t numEvent=nEvent;
protected:	
		void notify(size_t catalog)
		{
			for(list<Listener*const> ::iterator i=m_listenerCatalog[catalog].begin();i!=m_listenerCatalog[catalog].end();i++)
			{
				Listener* const t=*i;
				if(!t) continue;
				(t->*(t->OnEvents[catalog]))(getEvent());
			}
		}
		void notify_all()
		{
			for(size_t i=0;i<m_listnerCatalog.size();i++)
			{
				notify(i);
			}
		}
		//virtual EventClass* getEvent();
private:
	list<Listener*const > m_listenerList;
	
	size_t m_nCatalog;
	boost::ptr_vector< list<Listener*const > >m_listenerCatalog;
};


template <class ConMutiSource,class MutiListenerClass,size_t nEvent,class Param>
inline bool operator==(const MutiSource<ConMutiSource,MutiListenerClass,nEvent,Param>& clock1,const MutiSource<ConMutiSource,MutiListenerClass,nEvent,Param>& clock2)
{
	if(&clock1==&clock2)
		return true;
	else
		return false;
}


template <class ConMutiSource,class ConMutiListener,class Param>
class IMutiListener
{
	friend class MutiSource<ConMutiSource,ConMutiListener,ConMutiSource::numEvent,Param>;
protected:
	typedef typename MutiSource<ConMutiSource,ConMutiListener,ConMutiSource::numEvent,Param>::EventType SourceType;

	typedef void (ConMutiListener::*EventHandle)(SourceType&);
	vector<EventHandle> OnEvents;
	
	static const size_t numEvent=ConMutiSource::numEvent;
public:
	void add(vector<EventHandle>& list)
	{
		OnEvents.assign(list.begin(),list.end());
		if(list.size()!=numEvent)
			throw (FailToInitIMutiListener());
	}

	
};
